/**********************************************************************
项目名称/Project          : 基于CW32超低功耗水墨屏时钟
程序名称/Program name     : ESP-12F 获取网络天气
团队/Team                 : None
作者/Author               : 爱电子的梦兮
日期/Date（YYYYMMDD       : 2023/8/29
程序目的/Purpose          : 
本程序旨在通过手机配置WIFI后根据IP地址自动获取城市ID然后获取当地天气信息并通过串口将JSON数据发送至CW32。
如需了解本程序的详细说明，请参考以下函数：
***********************************************************************/
#include <Arduino.h>

#include <ESP8266WiFi.h>  //HTTP HTTPS
#include <ESP8266HTTPClient.h>
#include <ArduinoJson.h> //解析数据

#include <DNSServer.h>  //手机配置连接WIFI
#include <ESP8266WebServer.h>
#include <WiFiManager.h>

#include <SoftwareSerial.h>//软件串口与CW32通信
SoftwareSerial SoftSerial(4,5);//RX=GPIO4(D2)---TX=PB3,TX=GPIO5(D1)---RX=PB4

const char* GaoFen_KEY = "";//高分天气秘钥（自己去官网注册）
String City = "Taiyuan"; //保存城市IP 自动获取，获取失败则默认Taiyuan
String CityID = "101100101"; //保存城市ID

//天气信息：
String code;
float temp;
struct Daily_Fcsts{
  String code_day;
  String code_night;
  int8_t high;
  int8_t low;
  String date;
} today,tomorrow,acquired;
struct tm* timeInfo; //时间信息

char send_Json_buff[128];
void wificonnect(void);
void GetTime(void);
void GetCityIP(void);
void GetCityID(void);
void GetCurrentWeather(void);
void GetForeWeather(void);

void setup()
{
  Serial.begin(115200); //打印调试数据
  SoftSerial.begin(9600); //CW32串口处于深度睡眠状态低速时钟下仍可运行，但是波特率仅支持最高9600
  wificonnect();  //WIFI连接
  configTime(8*3600, 0*60, "ntp.ntsc.ac.cn", "ntp1.aliyun.com"); //npt获取时间
  delay(1000);  //等待WIFI稳定
}

void loop()
{
  delay(100); //喂狗
  if(SoftSerial.available()){
    char read_data = SoftSerial.read();
    Serial.print(read_data);
    //接收到更新数据指令
    if(read_data=='5') //time
    {
      GetTime();  //获取时间
      memset(send_Json_buff, 0, sizeof(send_Json_buff)); //清除发送缓存区
      sprintf(send_Json_buff,"{\"y\":%d,\"mo\":%d,\"d\":%d,\"h\":%d,\"m\":%d,\"s\":%d,\"w\":%d}",timeInfo->tm_year + 1900, timeInfo->tm_mon + 1, timeInfo->tm_mday, timeInfo->tm_hour, timeInfo->tm_min, timeInfo->tm_sec,timeInfo->tm_wday);
      SoftSerial.printf(send_Json_buff); //串口发送到CW23
    }
    else if(read_data=='6') //now
    {
      GetCityIP();
      GetCityID();
      GetCurrentWeather();
      memset(send_Json_buff, 0, sizeof(send_Json_buff));
      sprintf(send_Json_buff,"{\"c\":\"%s\",\"t\":%.1f,\"ip\":\"%s\"}",code,temp,City);
      SoftSerial.printf(send_Json_buff);
    }
    else if(read_data=='7') //today
    {
      GetForeWeather();
      memset(send_Json_buff, 0, sizeof(send_Json_buff));
      sprintf(send_Json_buff,"{\"d\":\"%s\",\"n\":\"%s\",\"h\":%d,\"l\":%d}",today.code_day,today.code_night,today.high,today.low);
      SoftSerial.printf(send_Json_buff);
    }
    else if(read_data=='8') //tomorrow
    {
      GetForeWeather();
      memset(send_Json_buff, 0, sizeof(send_Json_buff));
      sprintf(send_Json_buff,"{\"d\":\"%s\",\"n\":\"%s\",\"h\":%d,\"l\":%d}",tomorrow.code_day,tomorrow.code_night,tomorrow.high,tomorrow.low);
      SoftSerial.printf(send_Json_buff);
    }
    else if(read_data=='9') //acquired
    {
      GetForeWeather();
      memset(send_Json_buff, 0, sizeof(send_Json_buff));
      sprintf(send_Json_buff,"{\"d\":\"%s\",\"n\":\"%s\",\"h\":%d,\"l\":%d}",acquired.code_day,acquired.code_night,acquired.high,acquired.low);
      SoftSerial.printf(send_Json_buff);
    }
    else;
  }
}

// WIFI连接
void wificonnect()
{
  // 建立WiFiManager对象
  WiFiManager wifiManager;
  // 自动连接WiFi。以下语句的参数是连接ESP8266时的WiFi名称
  wifiManager.autoConnect("CW32 LPow Clock");
  Serial.print("WiFi Connected!");
  delay(500);
}

//获取时间
void GetTime(void)
{
  time_t now; //实例化时间
  now = time(nullptr);
  timeInfo = localtime(&now);
}

void GetCityIP() //步骤1
{
  WiFiClient client;
  HTTPClient http;
  String url = "http://ip-api.com/json/"; //获取IP
  http.begin(client,url);
  //启动连接并发送HTTP请求
  int httpCode = http.GET();
  if (httpCode == HTTP_CODE_OK) { //服务器响应
    String responsePayload = http.getString();
    //Serial.println(responsePayload);  //打印JSON数据
    //Cjson解析
    DynamicJsonDocument JsonBuf(1024);
    deserializeJson(JsonBuf, responsePayload);
    City = JsonBuf["city"].as<String>(); //获取到IP地址（拼音，如:chongqing）
    //Serial.println(City);

  } else { //服务器不响应
    //Serial.print("HTTP GET IP ERROR!");
  }
  http.end();//关闭ESP8266与服务器连接
}

void GetCityID(void) //步骤2
{
  WiFiClient client;
  HTTPClient http;
  //获取城市ID
  String url = "http://gfapi.mlogcn.com/function/v001/city?location="+City+"&items=10&area=china&language=CHN&withTz=false&withPoi=false&key="+GaoFen_KEY+"&output_type=json";
  http.begin(client,url);
  //启动连接并发送HTTP请求
  int httpCode = http.GET();
  if (httpCode == HTTP_CODE_OK) { //服务器响应
    String responsePayload = http.getString();
    //Serial.println(responsePayload);  //打印JSON数据
    //Cjson解析
    DynamicJsonDocument JsonBuf(1024);
    deserializeJson(JsonBuf, responsePayload);
    JsonObject areaList_0 = JsonBuf["areaList"][0];
    CityID = areaList_0["areacode"].as<String>();
    //Serial.println(CityID);
  } else { //服务器不响应
    //Serial.print("HTTP GET ID ERROR!");
  }
  http.end();//关闭ESP8266与服务器连接
}

//获取当地当前天气
void GetCurrentWeather() //步骤3
{
  //https协议
  std::unique_ptr<BearSSL::WiFiClientSecure>client(new BearSSL::WiFiClientSecure);
  client->setInsecure();
  HTTPClient https;
  //高分天气API
  String url = "https://gfapi.mlogcn.com/weather/v001/now?areacode="+CityID+"&key="+GaoFen_KEY+"&output_type=json";
  https.begin(*client, url);  //连接服务器 
  int httpCode = https.GET();
  if(httpCode == HTTP_CODE_OK || httpCode == HTTP_CODE_MOVED_PERMANENTLY) {
    String payload = https.getString();
    DynamicJsonDocument JsonBuf(1024);
    deserializeJson(JsonBuf, payload);
    temp = JsonBuf["result"]["realtime"]["temp"].as<float>();
    code = JsonBuf["result"]["realtime"]["code"].as<String>();
  }
  else Serial.println("HTTP GET Weather ERROR!");
  https.end();
}

//获取当地3天天气预报
void GetForeWeather() //同步骤3
{
  //https协议
  std::unique_ptr<BearSSL::WiFiClientSecure>client(new BearSSL::WiFiClientSecure);
  client->setInsecure();
  HTTPClient https;
  //高分天气API
  String url = "https://gfapi.mlogcn.com/weather/v001/day?areacode="+CityID+"&days=3&key="+GaoFen_KEY+"&output_type=json";
  https.begin(*client, url);  //连接服务器 
  int httpCode = https.GET();
  if(httpCode == HTTP_CODE_OK || httpCode == HTTP_CODE_MOVED_PERMANENTLY) {
    String payload = https.getString();
    DynamicJsonDocument JsonBuf(1024);
    deserializeJson(JsonBuf, payload);
    JsonObject daily_fcsts_0= JsonBuf["result"]["daily_fcsts"][0];
    JsonObject daily_fcsts_1= JsonBuf["result"]["daily_fcsts"][1];
    JsonObject daily_fcsts_2= JsonBuf["result"]["daily_fcsts"][2];

    today.code_day = daily_fcsts_0["code_day"].as<String>();
    today.code_night = daily_fcsts_0["code_night"].as<String>();
    today.high = daily_fcsts_0["high"].as<int>();
    today.low = daily_fcsts_0["low"].as<int>();
    today.date = daily_fcsts_0["date"].as<String>();

    tomorrow.code_day = daily_fcsts_1["code_day"].as<String>();
    tomorrow.code_night = daily_fcsts_1["code_night"].as<String>();
    tomorrow.high = daily_fcsts_1["high"].as<int>();
    tomorrow.low = daily_fcsts_1["low"].as<int>();
    tomorrow.date = daily_fcsts_1["date"].as<String>();

    acquired.code_day = daily_fcsts_2["code_day"].as<String>();
    acquired.code_night = daily_fcsts_2["code_night"].as<String>();
    acquired.high = daily_fcsts_2["high"].as<int>();
    acquired.low = daily_fcsts_2["low"].as<int>();
    acquired.date = daily_fcsts_2["date"].as<String>();
  }
  else Serial.println("HTTP GET Weather ERROR!");
  https.end();
}
